/* 
 * FileUtil.java
 * 
 * Data de criação: 02/04/2010
 * 
 * CORPORATIVO - MTE. 
 *
 */
package br.com.o2solutions.util.file;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;

import org.apache.commons.io.FileUtils;
import org.springframework.util.Assert;

import br.com.o2solutions.util.exception.FileUtilException;

/**
 * <p>
 * Classe responsável por realizar as operacoes uteis relacionadas a arquivos:
 * </p>
 * <ul>
 * <li>Leitura</li>
 * <li>Escrita</li>
 * <li>Criacao</li>
 * </ul>
 * 
 * @author osvaldeir
 * @since 02/04/2010
 * 
 */
public final class FileUtil {

	/**
	 * Construtor
	 */
	private FileUtil() {
	}

	/**
	 * Realiza a leitura de todas as linhas de um arquivo.
	 * 
	 * @param file
	 *            Arquivo a ser lido.
	 * @return List<String>
	 */
	@SuppressWarnings("unchecked")
	public static List<String> readLines(File file) {
		Assert.notNull(file, "Arquivo para leitura nao informado");
		List<String> readLines;
		try {
			readLines = FileUtils.readLines(file);
		} catch (IOException e) {
			throw new FileUtilException("Nao foi possivel ler o arquivo "
					.concat(file.getName()), e);
		}
		return readLines;
	}

	/**
	 * Realiza a escrita de linhas em um arquivo.
	 * 
	 * @param file
	 *            Arquivo a ser escrito
	 * @param lines
	 *            Linhas a serem inseridas.
	 */
	public static void writeLines(File file, Collection<String> lines) {
		Assert.notNull(file, "Arquivo para escrita nao informado");
		String errorMessage = "Valores a serem escritos o arquivos nao informados";
		Assert.notNull(lines, errorMessage);
		Assert.notEmpty(lines, errorMessage);
		try {
			FileUtils.writeLines(file, lines);
		} catch (IOException e) {
			throw new FileUtilException("Nao foi possivel escrever no arquivo "
					.concat(file.getName()), e);
		}
	}

	/**
	 * Realiza a extraçao de objetos do arquivo de acordo com o extrator.
	 * 
	 * @param <T>
	 *            Tipo de objetos a serem extraidos
	 * @param file
	 *            Arquivo contendo os dados
	 * @param extractor
	 *            Extrator
	 * @return List<T>
	 */
	public static <T> List<T> extractObjects(File file,
			Extractor<String, T> extractor) {
		List<T> result = new ArrayList<T>();
		List<String> lines = readLines(file);
		Iterator<String> iterator = lines.iterator();
		while (iterator.hasNext()) {
			result.add(extractor.extract(iterator.next()));
		}
		return result;
	}

	/**
	 * Move o arquivo para o destino especificado.Caso o arquivo não exista não
	 * é realizada nenhuma operacão.
	 * 
	 * @param source
	 *            File arquivo a ser movido.
	 * @param destiny
	 *            File destino do arquivo.
	 */
	public static void move(File source, File destiny) {
		Assert.notNull(source, "O arquivo a ser movido nao pode ser nulo");
		try {
			if (source.exists())
				FileUtils.moveFile(source, destiny);
		} catch (IOException e) {
			throw new FileUtilException("Nao foi possivel mover o arquivo "
					.concat(source.getAbsolutePath()), e);
		}
	}

	/**
	 * Remove o arquivo informado como parametro. Caso o arquivo nao exista e
	 * retornado null. Não é lancada uma excecao nos casos os quais o arquivo
	 * nao possa ser removido.
	 * 
	 * @param file
	 *            Arquivo a ser removido.
	 * @return boolean true caso o arquivo tenha sido removido.
	 */
	public static boolean removeFile(File file) {
		boolean returN = false;
		Assert.notNull(file, "O arquivo a ser removido nao pode ser nulo");
		returN = FileUtils.deleteQuietly(file);
		return returN;
	}

	/**
	 * Remove o diretorio passado como parametro. Caso este diretório não esteja
	 * vazio seus arquivos e subdiretorios tambem sao removidos. Caso o
	 * {@link File} nao seja um diretorio nao é realizada nenhuma acao.
	 * 
	 * @param file
	 *            Diretorio a ser removido
	 * @return boolean true Caso o diretorio tenha sido removido.
	 */
	public static boolean removeDirectory(File file) {
		boolean returN = false;
		Assert.notNull(file, "O arquivo a ser removido nao pode ser nulo");
		if (file.isDirectory())
			returN = FileUtils.deleteQuietly(file);
		return returN;
	}

	/**
	 * Remove o diretorio passado como parametro. Caso este diretório não esteja
	 * vazio seus arquivos e subdiretorios tambem sao removidos. Caso a
	 * {@link String} nao seja um diretorio nao é realizada nenhuma acao.
	 * 
	 * @param filePath
	 *            Caminho do diretorio a ser removido
	 * @return boolean true Caso o diretorio tenha sido removido.
	 */
	public static boolean removeDirectory(String filePath) {
		Assert.notNull(filePath,
				"O caminho do arquivo a ser removido nao pode ser nulo");
		File file = new File(filePath);
		return removeDirectory(file);
	}

	/**
	 * Cria um diretorio a parir de uma String.
	 * 
	 * @param dirPath
	 *            Diretorio a ser criado
	 * @return boolean true Caso o diretorio tenha sido criado.
	 */
	public static boolean createDir(String dirPath) {
		boolean returN = false;
		Assert.hasText(dirPath, "O caminho do diretorio nao pode ser nulo");
		File file = new File(dirPath);
		if (!file.exists()) {
			returN = file.mkdir();
		}
		return returN;
	}

	/**
	 * Remove todos os arquivos de um diretorio. O diretorio nao pode ser nulo e
	 * nem ser um arquivo. Neste ultimo caso nenhuma acao e realizada.
	 * 
	 * @param dir
	 *            Diretorio
	 */
	public static void removeAllFiles(File dir) {
		Assert.notNull(dir, "O diretorio nao pode ser nulo");
		if (dir.isDirectory()) {
			File[] files = dir.listFiles();
			if (files.length > 0) {
				for (File file : files) {
					file.delete();
				}
			}
		}
	}

	/**
	 * Remove todos os arquivos de um diretorio de acordo com o caminho
	 * informado. O diretorio nao pode ser nulo e nem ser um arquivo. Neste
	 * ultimo caso nenhuma acao e realizada.
	 * 
	 * @param String
	 *            Caminho do diretorio
	 */
	public static void removeAllFiles(String dirPath) {
		Assert.hasText(dirPath, "O caminnho o diretorio nao pode ser nulo");
		File dir = new File(dirPath);
		removeAllFiles(dir);
	}

	/**
	 * Cria um novo arquivo. Caso não seja possivel cria-lo (permissao de
	 * escrita, etc) e retornado false. Somente e lancada uma excecao caso o
	 * arquivo passado como parametro seja nulo.
	 * 
	 * @param file
	 *            {@link File} Arquivo a ser criado.
	 * @return boolean true caso o arquivo seja criado.
	 */
	public static boolean createFile(File file) {
		boolean returN = false;
		Assert.notNull(file, "O arquivo a ser criado não pode ser nulo");
		if (!file.exists()) {
			try {
				returN = file.createNewFile();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		return returN;
	}
}
